/*
 * Level.cpp
 *
 *  Created on: 06-Sep-2014
 *      Author: ali
 */

#include "Constant.h"
#include "Level.h"
#include "util.h"
#include "Message.h"
#include "Field.h"
#include "NodeContainer.h"
double dMaxDistanceToCH = 0;
Level::Level() :
		m_nLevel(0), m_dLen(0), m_dWidth(0), m_cMyPos(0, 0), m_iCHID(-1)
{

}
Node* Level::GetCH()
{
	return NodeContainer::GetNode(m_iCHID);
}
void Level::AddSensor(Node &node)
{
	m_vectorSensor.push_back(node.GetID());
}
void Level::SetLevel(int i)
{
	m_nLevel = i;
}
void Level::SetLen(double l)
{
	m_dLen = l;
}
void Level::SetWidth(double d)
{
	m_dWidth = d;
}
void Level::SetPos(Coordinate pos)
{
	m_cMyPos = pos;
}
double Level::GetLen()
{
	return m_dLen;
}
int Level::GetLevel()
{
	return m_nLevel;
}
double Level::GetWidth()
{
	return m_dWidth;
}
Coordinate Level::GetPos()
{
	return m_cMyPos;
}
bool Level::IsCoordinateInside(Coordinate otherPos)
{
	bool bStat = false;
	do
	{
		//check if x is in range
		if ((otherPos.GetXPos() >= m_cMyPos.GetXPos())
				&& (otherPos.GetXPos() < (m_dLen + m_cMyPos.GetXPos())))
		{
		}
		else
		{
			break;
		}
		//check if y is in range
		if ((otherPos.GetYPos() >= m_cMyPos.GetYPos())
				&& (otherPos.GetYPos() < (m_dWidth + m_cMyPos.GetYPos())))
		{
		}
		else
		{
			break;
		}
		bStat = true;
	} while (0);
	return bStat;
}

Node Level::GetCentralAciveSensor()
{
	Node centrtrl;
	bool bStatus = false;

	double dLeastDist = -1, curDist = -1;
	for (std::vector<int>::iterator it = m_vectorSensor.begin();
			it != m_vectorSensor.end(); ++it)
	{
		Node* pcurNode = NodeContainer::GetNode(*it);
		if (pcurNode == NULL)
		{
			continue;
		}

		if (false == pcurNode->GetNodeStatus())
		{
			continue;
		}
		curDist = (m_cSink.GetPos()).GetDistance(pcurNode->GetPos());
		if (dLeastDist == -1)
		{
			dLeastDist = curDist;
			centrtrl = *pcurNode;
			bStatus = true;
		}
		if (curDist < dLeastDist)
		{
			dLeastDist = curDist;
			centrtrl = *pcurNode;
		}
	}
	cout << "Level # " << m_nLevel << " Active Central Node # "
			<< centrtrl.GetID() << " Distance to Sink " << dLeastDist << endl;
	return centrtrl;
}

int Level::GetCHID()
{

	if (m_iCHID == -1)
	{
		return m_iCHID;
	}
	Node *pcCH = NULL;
	pcCH = NodeContainer::GetNode(m_iCHID);
	if (pcCH == NULL)
	{
		return -1;
	}
	if (pcCH->GetNodeStatus() == false)
	{
		return -1;
	}
	return m_iCHID;
}
bool Level::SendData(Node &nextLevelTarget)
{
	bool bStat = false;
	if (m_iCHID == -1)
	{
		return SendDirect(nextLevelTarget);
	}

	Node *pcCH = NULL;
	pcCH = NodeContainer::GetNode(m_iCHID);
	if (pcCH == NULL)
	{
		return false;
	}

	//pcCH->InitDataBuffer();
	//first ordinary sensor send data to CH
	cout << endl << "Send data Level# " << m_nLevel << " Node count# "
			<< m_vectorSensor.size() << " CH# " << pcCH->GetID()
			<< " Next Level Target Node # " << nextLevelTarget.GetID()
			<< " All Nodes ";
	for (std::vector<int>::iterator it = m_vectorSensor.begin();
			it != m_vectorSensor.end(); ++it)
	{
		Node *pcurNode = NULL;
		pcurNode = NodeContainer::GetNode(*it);
		if (pcurNode == NULL)
		{
			continue;
		}
		cout << "  " << pcurNode->GetID();
	}
	cout << endl;

	for (std::vector<int>::iterator it = m_vectorSensor.begin();
			it != m_vectorSensor.end(); ++it)
	{
		Node *pcurNode = NULL;
		pcurNode = NodeContainer::GetNode(*it);
		if (pcurNode == NULL)
		{
			continue;
		}
		if (false == pcurNode->GetNodeStatus())
		{
			continue;
		}
                

		if (pcurNode->GetID() != pcCH->GetID())
		{
			//normal node sends to CH of same level
			pcurNode->InitDataBuffer();
			pcurNode->AppendDataBuffer(DATA_MESSAGE_LENGTH);
                        double dDistanceToCH =
                            (pcurNode->GetPos()).GetDistance(pcCH->GetPos());

                        if (dMaxDistanceToCH<dDistanceToCH)
                        {
                            dMaxDistanceToCH = dDistanceToCH;
                           // cout <<"dMaxDistanceToCH " <<dMaxDistanceToCH<<endl;
                        }
                        if (dDistanceToCH>dTxRange )
                        {
        		            pcurNode->Send(nextLevelTarget);
                        }
                        else
                        {
            			    pcurNode->Send(*pcCH);
                        }
        
		}
		else
		{
			//CH node also has data ??
			//pcurNode->AppendDataBuffer(DATA_MESSAGE_LENGTH);
		}
	}
	//CH sends data to next level CH/Sink
	bStat = pcCH->Send(nextLevelTarget);
	return bStat;
}
bool Level::SendDirect(Node &nextLevelTarget)
{
	for (std::vector<int>::iterator it = m_vectorSensor.begin();
			it != m_vectorSensor.end(); ++it)
	{
		Node *pcurNode = NULL;
		pcurNode = NodeContainer::GetNode(*it);
		if (pcurNode == NULL)
		{
			continue;
		}
		if (false == pcurNode->GetNodeStatus())
		{
			continue;
		}
		//normal node sends directly to nextLevelTarget
		pcurNode->InitDataBuffer();
		pcurNode->AppendDataBuffer(DATA_MESSAGE_LENGTH);
		pcurNode->Send(nextLevelTarget);
	}
	return true;
}
int Level::GetActiveNode()
{
	int i = 0;
	for (std::vector<int>::iterator it = m_vectorSensor.begin();
			it != m_vectorSensor.end(); ++it)
	{
		Node* pcurNode = NodeContainer::GetNode(*it);
		if (false == pcurNode->GetNodeStatus())
		{
			continue;
		}
		if (pcurNode->GetResidualPower() < dMinPowerForCHSelection)
		{
			continue;
		}
		++i;
	}
	return i;
}
bool Level::SelectCH()
{
	bool bStat = false;
	bool bRetStat = false;
	int iActiveNodeCnt = GetActiveNode();
	if (m_vectorSensor.size() == 0)
	{
		return bRetStat;
	}
	if (iActiveNodeCnt < 2)
	{
		m_iCHID = -1;
		cout << "Level # " << m_nLevel << " No CH Can be selected" << endl;
		return bStat;
	}
	Node* pcCH = NULL;
	if (m_iCHID != -1)
	{
		pcCH = NodeContainer::GetNode(m_iCHID);
		if (pcCH->GetResidualPower() > dMinPowerToRemainCH)
		{
			return true;
		}
		else
		{
			cout << "Level # " << m_nLevel << " Node # " << m_iCHID
					<< " crossed threshold Power " << dMinPowerToRemainCH
					<< " Current Residual power " << pcCH->GetResidualPower()
					<< endl;
			// make it normal sensor
			pcCH->SetNodeType(eNormalSensor);
			m_iCHID = -1;
		}
	}
	Node centrlNode = GetCentralAciveSensor();
	if (centrlNode.GetID() == -1)
	{
		return bRetStat;
	}

	Node* pNewCHCandidate = NodeContainer::GetNode(centrlNode.GetID());

	Node* pOldCHCandidate = pNewCHCandidate;
// do CH Selection loop
//first node start the process

	do
	{
		bStat = pNewCHCandidate->SendCHSelectionMsg();
		if (false == bStat)
		{
			m_iCHID = -1;
			//all nodes in this level dead
			return bStat;
		}
		else
		{
			m_iCHID = pNewCHCandidate->GetID();
			bRetStat = true;
		}

		for (std::vector<int>::iterator it = m_vectorSensor.begin();
				it != m_vectorSensor.end(); ++it)
		{
			Node* pcurNode = NodeContainer::GetNode(*it);
			if (false == pcurNode->GetNodeStatus())
			{
				continue;
			}
			//Receive Broadcast CH Selection message
			//non-central nodes
			if (pcurNode->GetID() != pNewCHCandidate->GetID())
			{
				pcurNode->RecvCHSelectionMsg();
			}
		}

		for (std::vector<int>::iterator it = m_vectorSensor.begin();
				it != m_vectorSensor.end(); ++it)
		{
			Node* pcurNode = NodeContainer::GetNode(*it);
			if (false == pcurNode->GetNodeStatus())
			{
				continue;
			}//process CH Selection message and Reply with CH Selection message if its better
			if (pcurNode->GetID() != pNewCHCandidate->GetID())
			{
				bStat = pcurNode->IsBetterCH();
				if (true == bStat)
				{
					pNewCHCandidate = pcurNode;
					break; //only one node reply for current iteration
				}
			}
		}
		if (pNewCHCandidate->GetID() == pOldCHCandidate->GetID())
		{
			break;
		}
		else
		{
			pOldCHCandidate = pNewCHCandidate;
		}
	} while (1);
	if (true == bRetStat)
	{
		pNewCHCandidate->SetNodeType(eCHSensor);
		pNewCHCandidate->IncreaseCHSelectionWinner();
		cout << "Level # " << m_nLevel << " Node # " << pNewCHCandidate->GetID()
				<< " Selected as CH with Residual power "
				<< pNewCHCandidate->GetResidualPower() << endl;
	}
	else
	{
		cout << "Level # " << m_nLevel << " No CH Found" << endl;
	}
	return bRetStat;

}
Level::~Level()
{

}

ostream & operator<<(ostream & out, Level & l)
{
	out << "Level ID " << l.GetLevel() << " X: " << (l.GetPos()).GetXPos()
			<< " Y: " << (l.GetPos()).GetYPos() << " Node Count "
			<< l.m_vectorSensor.size() << endl;

	for (std::vector<int>::iterator itNode = l.m_vectorSensor.begin();
			itNode != l.m_vectorSensor.end(); ++itNode)
	{
		Node *pnode = NodeContainer::GetNode(*itNode);
		out << *pnode;
	}
	return out;
}
